package com.ywu.application.standard.thirdExec.service;

import com.ywu.boot.context.YwuContextHolder;
import com.ywu.boot.exception.YwuRuntimeException;
import com.ywu.common.result.CommonResult;
import com.ywu.common.utils.TimerIdGenerateUtil;
import com.ywu.file.sys.sdk.enter.YwuFileSysExec;
import com.ywu.application.standard.thirdExec.config.YwuThirdExecConfig;
import com.ywu.application.standard.thirdExec.constant.YwuThirdExecConstant;
import com.ywu.application.standard.thirdExec.data.YwuThirdExecRepository;
import com.ywu.application.standard.thirdExec.data.YwuThirdExecVersionRepository;
import com.ywu.application.standard.thirdExec.dto.YwuThirdExecDto;
import com.ywu.application.standard.thirdExec.dto.YwuThirdExecVersionDto;
import com.ywu.application.standard.thirdExec.entity.YwuThirdExecEntity;
import com.ywu.application.standard.thirdExec.entity.YwuThirdExecVersionEntity;
import com.ywu.application.standard.thirdExec.exec.DoThirdExecCoreService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.benf.cfr.reader.api.CfrDriver;
import org.benf.cfr.reader.util.getopt.OptionsImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @ClassName YwuThirdExecVersionService
 * @Description TODO
 * @Author GroundDemo
 * @Date 2024/10/11 14:41
 * @Version 1.0
 **/
@Service
@Slf4j
public class YwuThirdExecVersionService {
    @Autowired
    private YwuThirdExecVersionRepository ywuThirdExecVersionRepository;

    @Autowired
    private YwuThirdExecRepository ywuThirdExecRepository;

    @Autowired
    private YwuFileSysExec ywuFileSysExec;

    @Autowired
    private DoThirdExecCoreService doThirdExecCoreService;

    @Autowired
    private YwuThirdExecConfig config;

    /**
    * @Author GroundDemo
    * @Description 查询执行脚本的历史版本
    * @Date 15:05 2024/10/11
    * @Param [thirdExecVersionDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> queryThirdExecVersionList(YwuThirdExecVersionDto thirdExecVersionDto) {
        // 根据resourceId查询历史版本列表
        YwuThirdExecVersionEntity ywuThirdExecVersionEntity = new YwuThirdExecVersionEntity();
        ywuThirdExecVersionEntity.setResourceId(thirdExecVersionDto.getResourceId());
        List<YwuThirdExecVersionEntity> resList = ywuThirdExecVersionRepository.queryVersionList(ywuThirdExecVersionEntity);
        ArrayList<YwuThirdExecVersionEntity> result = new ArrayList<>();
        if (CollectionUtils.isEmpty(resList)) {
            return CommonResult.success(result);
        }
        // 如果最后一条数据的版本为0，将其放置在首位
        if (resList.get(resList.size() - 1).getVersion() == 0) {
            YwuThirdExecVersionEntity draftEntity = resList.get(resList.size() - 1);
            resList.remove(resList.size() - 1);
            result.add(draftEntity);
        }
        result.addAll(resList);
        return CommonResult.success(result);
    }

    /**
    * @Author GroundDemo
    * @Description 删除草稿版本的数据
    * @Date 15:07 2024/10/11
    * @Param [thirdExecVersionDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> deleteDraftVersion(YwuThirdExecVersionDto thirdExecVersionDto) {
        // resourceId删除草稿版本数据
        YwuThirdExecVersionEntity ywuThirdExecVersionEntity = new YwuThirdExecVersionEntity();
        ywuThirdExecVersionEntity.setVersion(0);
        ywuThirdExecVersionEntity.setResourceId(thirdExecVersionDto.getResourceId());
        ywuThirdExecVersionRepository.deleteByIdAndVersion(ywuThirdExecVersionEntity);
        // 更改原始表中的hasNotReleased字段
        YwuThirdExecEntity ywuThirdExecEntity = new YwuThirdExecEntity();
        ywuThirdExecEntity.setId(thirdExecVersionDto.getResourceId());
        ywuThirdExecEntity.setHasNotReleased(false);
        ywuThirdExecEntity.updateInfo(YwuContextHolder.getCurrentContext().getYwuContextUser().getUserAccount());
        ywuThirdExecRepository.updateThirdExec(ywuThirdExecEntity);
        return CommonResult.success(null);
    }

    /**
    * @Author GroundDemo
    * @Description 回退历史版本的数据
    * @Date 15:08 2024/10/11
    * @Param [thirdExecVersionDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> backThirdExecVersion(YwuThirdExecVersionDto thirdExecVersionDto) {
        // 查询待回退的版本信息
        YwuThirdExecVersionEntity search = new YwuThirdExecVersionEntity();
        search.setResourceId(thirdExecVersionDto.getResourceId());
        search.setVersion(thirdExecVersionDto.getVersion());
        YwuThirdExecVersionEntity queryEntity = ywuThirdExecVersionRepository.getEntity(search);
        // 添加草稿版本信息
        addDraftInfo(queryEntity);
        // 修改hasNotReleased状态
        YwuThirdExecEntity ywuThirdExecEntity = new YwuThirdExecEntity();
        ywuThirdExecEntity.setId(thirdExecVersionDto.getResourceId());
        ywuThirdExecEntity.setHasNotReleased(true);
        ywuThirdExecEntity.updateInfo(YwuContextHolder.getCurrentContext().getYwuContextUser().getUserAccount());
        ywuThirdExecRepository.updateThirdExec(ywuThirdExecEntity);
        return CommonResult.success(null);
    }

    /**
    * @Author GroundDemo
    * @Description 添加草稿版本信息
    * @Date 15:02 2024/10/12
    * @Param [queryEntity]
    * @return void
    **/
    private void addDraftInfo(YwuThirdExecVersionEntity queryEntity) {
        // 构建参数，沿用方法
        YwuThirdExecDto ywuThirdExecDto = new YwuThirdExecDto();
        BeanUtils.copyProperties(queryEntity, ywuThirdExecDto);
        ywuThirdExecDto.setId(queryEntity.getResourceId());
        updateDraftVersionInfo(ywuThirdExecDto);
    }

    /**
    * @Author GroundDemo
    * @Description 更新草稿版本的数据
    * @Date 15:27 2024/10/11
    * @Param [ywuThirdExecDto]
    * @return void
    **/
    public void updateDraftVersionInfo(YwuThirdExecDto ywuThirdExecDto) {
        // 根据当前resourceId查询草稿版本的数据，如果不存在，则重新插入草稿版本的数据
        YwuThirdExecVersionEntity search = new YwuThirdExecVersionEntity();
        search.setResourceId(ywuThirdExecDto.getId());
        search.setVersion(0);
        YwuThirdExecVersionEntity queryRes = ywuThirdExecVersionRepository.getEntity(search);
        if (Objects.isNull(queryRes)) {
            // 新增一条草稿
            YwuThirdExecVersionEntity insertEntity = new YwuThirdExecVersionEntity();
            BeanUtils.copyProperties(ywuThirdExecDto, insertEntity);
            insertEntity.setId(TimerIdGenerateUtil.nextId());
            insertEntity.setVersion(0);
            insertEntity.setResourceId(ywuThirdExecDto.getId());
            insertEntity.createInfo(YwuContextHolder.getCurrentContext().getYwuContextUser().getUserAccount());
            ywuThirdExecVersionRepository.insertVersionInfo(insertEntity);
        } else {
            YwuThirdExecVersionEntity updateEntity = new YwuThirdExecVersionEntity();
            // 构建参数
            updateEntity.setVersion(0);
            updateEntity.setResourceId(ywuThirdExecDto.getId());
            updateEntity.setId(queryRes.getId());
            updateEntity.setContentUrl(queryRes.getContentUrl());
            updateEntity.setExecType(ywuThirdExecDto.getExecType());
            updateEntity.setExecParam(ywuThirdExecDto.getExecParam());
            updateEntity.setDescription(ywuThirdExecDto.getDescription());
            updateEntity.updateInfo(YwuContextHolder.getCurrentContext().getYwuContextUser().getUserAccount());
            ywuThirdExecVersionRepository.updateVersionInfo(updateEntity);
        }
    }

    /**
    * @Author GroundDemo
    * @Description 批量查询草稿版本的数据
    * @Date 15:46 2024/10/11
    * @Param [resourceIds]
    * @return java.util.List<com.ywu.third.exec.standard.entity.YwuThirdExecVersionEntity>
    **/
    public List<YwuThirdExecVersionEntity> queryDraftListByResourceIds(List<String> resourceIds) {
        return ywuThirdExecVersionRepository.queryDraftListByResourceIds(resourceIds);
    }

    /**
    * @Author GroundDemo
    * @Description 修改草稿版本中的contentUrl字段
    * @Date 12:05 2024/10/12
    * @Param [uploadRes, queryRes]
    * @return void
    **/
    public void updateVersionContentUrl(Map<String, String> uploadRes, YwuThirdExecEntity ywuThirdExecEntity) {
        // 根据当前resourceId查询草稿版本的数据，如果不存在，则重新插入草稿版本的数据
        YwuThirdExecVersionEntity search = new YwuThirdExecVersionEntity();
        search.setResourceId(ywuThirdExecEntity.getId());
        search.setVersion(0);
        YwuThirdExecVersionEntity queryRes = ywuThirdExecVersionRepository.getEntity(search);
        if (Objects.isNull(queryRes)) {
            // 新增一条草稿
            YwuThirdExecVersionEntity insertEntity = new YwuThirdExecVersionEntity();
            BeanUtils.copyProperties(ywuThirdExecEntity, insertEntity);
            insertEntity.setId(TimerIdGenerateUtil.nextId());
            insertEntity.setResourceId(ywuThirdExecEntity.getId());
            insertEntity.setVersion(0);
            insertEntity.setContentUrl(uploadRes.get("fileUrl"));
            insertEntity.createInfo(YwuContextHolder.getCurrentContext().getYwuContextUser().getUserAccount());
            ywuThirdExecVersionRepository.insertVersionInfo(insertEntity);
        } else {
            queryRes.setContentUrl(uploadRes.get("fileUrl"));
            queryRes.updateInfo(YwuContextHolder.getCurrentContext().getYwuContextUser().getUserAccount());
            ywuThirdExecVersionRepository.updateVersionInfo(queryRes);
        }
    }

    /**
    * @Author GroundDemo
    * @Description 添加最新版本的数据
    * @Date 14:41 2024/10/12
    * @Param [queryRes]
    * @return void
    **/
    public void publishNewestVersion(YwuThirdExecEntity queryRes) {
        YwuThirdExecVersionEntity ywuThirdExecVersionEntity = new YwuThirdExecVersionEntity();
        BeanUtils.copyProperties(queryRes, ywuThirdExecVersionEntity);
        ywuThirdExecVersionEntity.setVersion(queryRes.getCurrentVersion() + 1);
        ywuThirdExecVersionEntity.setResourceId(queryRes.getId());
        ywuThirdExecVersionEntity.setId(TimerIdGenerateUtil.nextId());
        ywuThirdExecVersionEntity.createInfo(YwuContextHolder.getCurrentContext().getYwuContextUser().getUserAccount());
        ywuThirdExecVersionRepository.insertVersionInfo(ywuThirdExecVersionEntity);
    }

    /**
    * @Author GroundDemo
    * @Description 发布草稿版本的数据
    * @Date 14:44 2024/10/12
    * @Param [queryRes]
    * @return void
    **/
    public YwuThirdExecVersionEntity publishDraftVersion(YwuThirdExecEntity queryRes) {
        // 根据当前的resourceId查询草稿版本的数据
        YwuThirdExecVersionEntity search = new YwuThirdExecVersionEntity();
        search.setResourceId(queryRes.getId());
        search.setVersion(0);
        YwuThirdExecVersionEntity query = ywuThirdExecVersionRepository.getEntity(search);
        // 修改当前的版本号
        YwuThirdExecVersionEntity updateEntity = new YwuThirdExecVersionEntity();
        updateEntity.setId(query.getId());
        updateEntity.setVersion(queryRes.getCurrentVersion() + 1);
        updateEntity.updateInfo(YwuContextHolder.getCurrentContext().getYwuContextUser().getUserAccount());
        ywuThirdExecVersionRepository.updateVersionInfo(updateEntity);
        return query;
    }

    /**
    * @Author GroundDemo
    * @Description 脚本内容查看
    * @Date 19:20 2024/10/15
    * @Param [thirdExecVersionDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> thirdExecContentView(YwuThirdExecVersionDto thirdExecVersionDto) {
        // 根据当前ID和版本查询对应的数据
        YwuThirdExecVersionEntity search = new YwuThirdExecVersionEntity();
        search.setResourceId(thirdExecVersionDto.getResourceId());
        search.setVersion(thirdExecVersionDto.getVersion());
        YwuThirdExecVersionEntity entity = ywuThirdExecVersionRepository.getEntity(search);
        if (Objects.isNull(entity)) {
            return CommonResult.error().setCode(YwuThirdExecConstant.RESOURCE_NOT_EXISTS_CODE)
                    .setErrorCode(YwuThirdExecConstant.RESOURCE_NOT_EXISTS_ERROR_CODE)
                    .setMessage(YwuThirdExecConstant.RESOURCE_NOT_EXISTS_ERROR_MESSAGE);
        }
        if (StringUtils.isEmpty(entity.getContentUrl())) {
            return CommonResult.success("");
        }
        // 如果类型为class或者jar包，直接返回空串
        if (entity.getExecType().equals(YwuThirdExecEntity.EXEC_TYPE_JAVA_JAR)) {
            return CommonResult.success("");
        }
        // 根据url获取对应的fileId
        String contentUrl = entity.getContentUrl();
        String[] urlList = contentUrl.split("/");
        String fileId = urlList[urlList.length - 1];
        String filePath = ywuFileSysExec.download(fileId);
        String res = "";
        if (entity.getExecType().equals(YwuThirdExecEntity.EXEC_TYPE_JAVA_CLASS)) {
            // class文件需要反编译成java文件
            res = getClassContent(filePath, fileId);
        } else {
            res = getCommonContent(filePath);
        }
        return CommonResult.success(res);
    }

    /**
    * @Author GroundDemo
    * @Description 查询class反编译后的java内容
    * @Date 11:49 2024/10/18
    * @Param [filePath]
    * @return java.lang.String
    **/
    private String getClassContent(String filePath, String fileId) {
        String javaPathDir = config.getTempFilePath() + File.separator + "javas";
        File javaPathDirFile = new File(javaPathDir);
        if (!javaPathDirFile.exists() && !javaPathDirFile.mkdirs()) {
            log.error("getClassContent dir make error");
            return null;
        }
        String destFileDirPath = javaPathDir + File.separator + fileId;
        try {
            List<String> files = new ArrayList<>();
            files.add(filePath);
            // target dir
            HashMap<String, String> outputMap = new HashMap<>();
            outputMap.put("outputdir", destFileDirPath);
            outputMap.put("hideutf", "false");
            OptionsImpl options = new OptionsImpl(outputMap);
            CfrDriver cfrDriver = new CfrDriver.Builder().withBuiltOptions(options).build();
            cfrDriver.analyse(files);
        } catch (Exception e) {
            log.error("getClassContent class parse error");
            return null;
        } finally {
            File file = new File(filePath);
            file.delete();
        }
        // 读取文件中的数据
        StringBuilder res = new StringBuilder();
        // 获取目标目录下的所有class文件
        File destDirFile = new File(destFileDirPath);
        File[] files = destDirFile.listFiles();
        if (Objects.isNull(files)) {
            log.warn("file list is empty");
            return res.toString();
        }
        BufferedInputStream bufferedInputStream = null;
        try {
            for (File f : files) {
                String fileName = f.getName();
                bufferedInputStream = new BufferedInputStream(new FileInputStream(f));
                if (fileName.endsWith(".java")) {
                    res.append(fileName).append(" 字节码预览").append("\n\n");
                    int size = bufferedInputStream.available();
                    final byte[] buffer = new byte[size];
                    while (bufferedInputStream.read(buffer) > -1) {
                        res.append(new String(buffer, StandardCharsets.UTF_8));
                    }
                }
                bufferedInputStream.close();
                bufferedInputStream = null;
            }
        } catch (IOException e) {
            log.error("IO Exception {}", e.getMessage());
            throw new YwuRuntimeException(e.getMessage());
        } finally {
            if (Objects.nonNull(bufferedInputStream)) {
                try {
                    bufferedInputStream.close();
                } catch (IOException e) {
                    log.error("bufferedInputStream close error");
                }
            }
            try {
                FileUtils.deleteDirectory(destDirFile);
            } catch (IOException e) {
                log.error("destDirFile delete error");
            }
        }
        return res.toString();
    }

    /**
    * @Author GroundDemo
    * @Description 查询脚本文件的内容
    * @Date 11:48 2024/10/18
    * @Param [filePath]
    * @return java.lang.String
    **/
    private String getCommonContent(String filePath) {
        String res = "";
        try(BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath))) {
            final byte[] buffer = new byte[bufferedInputStream.available()];
            while (bufferedInputStream.read(buffer) > -1) {
                res = new String(buffer, StandardCharsets.UTF_8);
            }
        } catch (IOException e) {
            log.error("IO Exception {}", e.getMessage());
            throw new YwuRuntimeException(e.getMessage());
        } finally {
            File file = new File(filePath);
            file.delete();
        }
        return res;
    }

    /**
    * @Author GroundDemo
    * @Description 执行历史版本的脚本
    * @Date 22:14 2024/10/15
    * @Param [thirdExecVersionDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> doThirdExecVersion(YwuThirdExecVersionDto thirdExecVersionDto) {
        // 根据resourceId和version查询数据
        YwuThirdExecVersionEntity search = new YwuThirdExecVersionEntity();
        search.setVersion(thirdExecVersionDto.getVersion());
        search.setResourceId(thirdExecVersionDto.getResourceId());
        YwuThirdExecVersionEntity query = ywuThirdExecVersionRepository.getEntity(search);
        if (Objects.isNull(query)) {
            return CommonResult.error().setCode(YwuThirdExecConstant.RESOURCE_NOT_EXISTS_CODE)
                    .setErrorCode(YwuThirdExecConstant.RESOURCE_NOT_EXISTS_ERROR_CODE)
                    .setMessage(YwuThirdExecConstant.RESOURCE_NOT_EXISTS_ERROR_MESSAGE);
        }
        if (StringUtils.isEmpty(query.getContentUrl())) {
            return CommonResult.error().setCode(YwuThirdExecConstant.RESOURCE_NO_EXEC_CONTENT_CODE)
                    .setErrorCode(YwuThirdExecConstant.RESOURCE_NO_EXEC_CONTENT_ERROR_CODE)
                    .setMessage(YwuThirdExecConstant.RESOURCE_NO_EXEC_CONTENT_ERROR_MESSAGE);
        }
        // 构建参数
        YwuThirdExecEntity ywuThirdExecEntity = new YwuThirdExecEntity();
        BeanUtils.copyProperties(query, ywuThirdExecEntity);
        ywuThirdExecEntity.setCurrentVersion(query.getVersion());
        ywuThirdExecEntity.setId(query.getResourceId());
        ywuThirdExecEntity.setExecParam(thirdExecVersionDto.getExecParam());
        String execRes = doThirdExecCoreService.exec(ywuThirdExecEntity);
        return CommonResult.success(execRes);
    }

    /**
    * @Author GroundDemo
    * @Description 根据resourceId删除所有的历史数据
    * @Date 11:44 2024/10/16
    * @Param [ywuThirdExecVersionEntity]
    * @return void
    **/
    public void deleteExecVersions(YwuThirdExecVersionEntity ywuThirdExecVersionEntity) {
        ywuThirdExecVersionRepository.deleteExecVersionsByResourceId(ywuThirdExecVersionEntity);
    }

    /**
    * @Author GroundDemo
    * @Description 查询历史版本信息
    * @Date 11:44 2024/10/16
    * @Param [thirdExecVersionDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> thirdExecVersionInfo(YwuThirdExecVersionDto thirdExecVersionDto) {
        YwuThirdExecVersionEntity search = new YwuThirdExecVersionEntity();
        search.setResourceId(thirdExecVersionDto.getResourceId());
        search.setVersion(thirdExecVersionDto.getVersion());
        YwuThirdExecVersionEntity query = ywuThirdExecVersionRepository.getEntity(search);
        return CommonResult.success(query);
    }
}
